package cn.mujiankeji.mbrowser.功能.浏览框.助手

import android.app.AlertDialog
import android.content.DialogInterface
import android.util.Log
import android.webkit.CookieManager
import android.webkit.JavascriptInterface
import androidx.annotation.Keep
import cn.mujiankeji.mbrowser.app.应用接口
import cn.mujiankeji.mbrowser.工具.网络.网络操作
import cn.mujiankeji.mbrowser.数据.配置项.应用配置
import cn.mujiankeji.mbrowser.功能.浏览框.浏览框状态
import cn.mujiankeji.mbrowser.工具.mlog
import com.blankj.utilcode.util.ClipboardUtils
import com.blankj.utilcode.util.EncodeUtils
import com.blankj.utilcode.util.FileIOUtils
import com.blankj.utilcode.util.FileUtils
import com.blankj.utilcode.util.GsonUtils
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import okhttp3.Credentials
import okhttp3.Headers
import org.json.JSONException
import org.json.JSONObject
import 操作.工具类.文本操作
import java.io.File
import java.net.SocketTimeoutException
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

/**
 * 油猴脚本接口
 * 
 * 这个类用于在Android WebView中实现 Tampermonkey/Greasemonkey 等桌面浏览器油猴扩展的API
 * 主要功能包括:
 * 1. 提供网络请求功能 (xmlhttpRequest)
 * 2. 脚本数据存储 (setValue/getValue/listValues)
 * 3. 菜单注册与管理
 * 4. 通知和交互
 * 5. 资源加载与处理
 * 
 * 可通过JavaScript调用这些函数，实现与桌面浏览器油猴脚本相同的功能
 */
@Keep
open class 浏览框油猴脚本兼容交互助手(val state : 浏览框状态) : KoinComponent {

    // 通过 Koin 获取 HttpClient
    private val httpClient: HttpClient by inject()

    // 脚本存储数据缓存，避免频繁文件IO
    private val 脚本数据缓存 = ConcurrentHashMap<String, JSONObject>()
    
    // 用于同步对同一个配置文件的读写操作，避免并发问题
    private val 文件锁 = ConcurrentHashMap<String, ReentrantReadWriteLock>()
    
    // 油猴脚本存储目录
    private val 脚本存储目录: String by lazy { 
        val dir = 应用配置.路径_用户脚本 + "config/"
        FileUtils.createOrExistsDir(dir)
        dir
    }

    // unsafeWindow   该方法是获取window对象，应从JS中插入
    // JS实现：  const unsafeWindow = window.wrappedJSObject || window;

    /**
     * 执行网络请求并返回响应
     *
     * @param url 请求URL
     * @param method 请求方法 (GET, POST, PUT等)
     * @param headers 请求头
     * @param body 请求体
     * @param redirect 是否跟随重定向
     * @param timeout 超时时间(毫秒)
     * @param binary 是否返回二进制数据
     * @return 请求响应对象
     */
    private suspend fun 执行网络请求(
        url: String,
        method: String,
        headers: Map<String, String>,
        body: String = "",
        redirect: Boolean = true,
        timeout: Int = 0,
        binary: Boolean = false,
        responseType: String = "text"
    ): xmlHttpResponse {
        val response = xmlHttpResponse()
        response.finalUrl = url
        
        try {
            // 如果需要禁用重定向，创建一个临时的HttpClient
            val client = if (!redirect) {
                httpClient.config { 
                    followRedirects = false 
                }
            } else {
                httpClient
            }
            
            when (method.uppercase()) {
                "GET" -> {
                    // 使用网络操作工具类发送GET请求
                    if (binary || responseType == "arraybuffer" || responseType == "stream") {
                        // 二进制响应
                        val bytes = 网络操作.获取字节(
                            url = url,
                            headers = headers,
                            超时 = timeout.toLong().takeIf { it > 0 }
                        )
                        
                        if (bytes != null) {
                            response.status = 200
                            response.statusText = "OK"
                            response.response = EncodeUtils.base64Encode2String(bytes)
                        } else {
                            throw Exception("请求失败")
                        }
                    } else {
                        // 文本响应
                        val text = 网络操作.获取文本(
                            url = url,
                            headers = headers,
                            outTimer = timeout.toLong().takeIf { it > 0 }
                        )
                        
                        if (text != null) {
                            response.status = 200
                            response.statusText = "OK"
                            response.response = text
                        } else {
                            throw Exception("请求失败")
                        }
                    }
                }
                
                "POST" -> {
                    // 判断Content-Type
                    val contentType = headers["Content-Type"] ?: ""
                    
                    if (contentType.contains("json") || (body.startsWith("{") && body.endsWith("}"))) {
                        // JSON请求
                        val responseText = 网络操作.提交JSON(
                            url = url,
                            json = body,
                            headers = headers,
                            超时 = timeout.toLong().takeIf { it > 0 }
                        )
                        
                        if (responseText != null) {
                            response.status = 200
                            response.statusText = "OK"
                            response.response = responseText
                        } else {
                            throw Exception("请求失败")
                        }
                    } else if (contentType.contains("form-urlencoded")) {
                        // 表单请求
                        val formData = mutableMapOf<String, String>()
                        
                        // 解析表单数据
                        val formItems = body.split("&")
                        for (item in formItems) {
                            val parts = item.split("=", limit = 2)
                            if (parts.size == 2) {
                                val key = parts[0]
                                val value = parts[1]
                                formData[key] = value
                            }
                        }
                        
                        val responseText = 网络操作.提交表单(
                            url = url,
                            表单数据 = formData,
                            headers = headers,
                            超时 = timeout.toLong().takeIf { it > 0 }
                        )
                        
                        if (responseText != null) {
                            response.status = 200
                            response.statusText = "OK"
                            response.response = responseText
                        } else {
                            throw Exception("请求失败")
                        }
                    } else {
                        // 其他类型POST请求，使用Ktor HttpClient
                        val timeoutMs = if (timeout == 0) 20000L else timeout.toLong()
                        
                        val httpResponse = client.post(url) {
                            // 设置超时
                            timeout {
                                requestTimeoutMillis = timeoutMs
                                connectTimeoutMillis = timeoutMs
                                socketTimeoutMillis = timeoutMs
                            }
                            
                            // 设置请求头
                            headers.forEach { (key, value) ->
                                header(key, value)
                            }
                            
                            // 设置请求体
                            val mediaType = contentType.takeIf { it.isNotEmpty() } ?: "text/plain"
                            setBody(body)
                            contentType(ContentType.parse(mediaType))
                        }
                        
                        response.status = httpResponse.status.value
                        response.statusText = httpResponse.status.description
                        
                        // 将Ktor响应头转换为Headers对象
                        val headersBuilder = Headers.Builder()
                        httpResponse.headers.forEach { name, values ->
                            values.forEach { value ->
                                headersBuilder.add(name, value)
                            }
                        }
                        response.responseHeaders = headersBuilder.build()
                        
                        if (httpResponse.status.value in 300..399) {
                            response.finalUrl = httpResponse.headers["Location"] ?: response.finalUrl
                        }
                        
                        if (binary || responseType == "arraybuffer" || responseType == "stream") {
                            val bytes = httpResponse.body<ByteArray>()
                            response.response = EncodeUtils.base64Encode2String(bytes)
                        } else {
                            response.response = httpResponse.bodyAsText()
                        }
                    }
                }
                
                "HEAD" -> {
                    // 使用网络操作工具类发送HEAD请求
                    val responseHeaders = 网络操作.获取资源信息(
                        url = url,
                        headers = headers,
                        超时 = timeout.toLong().takeIf { it > 0 }
                    )
                    
                    if (responseHeaders.isNotEmpty()) {
                        response.status = 200
                        response.statusText = "OK"
                        // 转换响应头格式
                        val headersBuilder = Headers.Builder()
                        responseHeaders.forEach { (key, values) ->
                            values.forEach { value ->
                                headersBuilder.add(key, value)
                            }
                        }
                        response.responseHeaders = headersBuilder.build()
                    } else {
                        throw Exception("请求失败")
                    }
                }
                
                else -> {
                    // 其他请求方法，使用Ktor HttpClient
                    val timeoutMs = if (timeout == 0) 20000L else timeout.toLong()
                    
                    val httpResponse = client.request(url) {
                        // 设置请求方法
                        this.method = HttpMethod.parse(method)
                        
                        // 设置超时
                        timeout {
                            requestTimeoutMillis = timeoutMs
                            connectTimeoutMillis = timeoutMs
                            socketTimeoutMillis = timeoutMs
                        }
                        
                        // 设置请求头
                        headers.forEach { (key, value) ->
                            header(key, value)
                        }
                        
                        // 根据请求方法添加请求体
                        when (method.uppercase()) {
                            "PUT", "PATCH", "DELETE" -> {
                                if (body.isNotEmpty()) {
                                    val mediaType = headers["Content-Type"] ?: "text/plain"
                                    setBody(body)
                                    contentType(ContentType.parse(mediaType))
                                }
                            }
                        }
                    }
                    
                    response.status = httpResponse.status.value
                    response.statusText = httpResponse.status.description
                    
                    // 将Ktor响应头转换为Headers对象
                    val headersBuilder = Headers.Builder()
                    httpResponse.headers.forEach { name, values ->
                        values.forEach { value ->
                            headersBuilder.add(name, value)
                        }
                    }
                    response.responseHeaders = headersBuilder.build()
                    
                    if (httpResponse.status.value in 300..399) {
                        response.finalUrl = httpResponse.headers["Location"] ?: response.finalUrl
                    }
                    
                    if (binary || responseType == "arraybuffer" || responseType == "stream") {
                        val bytes = httpResponse.body<ByteArray>()
                        response.response = EncodeUtils.base64Encode2String(bytes)
                    } else {
                        response.response = httpResponse.bodyAsText()
                    }
                }
            }
        } catch (e: Exception) {
            response.status = -1
            response.statusText = e.toString()
            throw e
        }
        
        return response
    }

    /**
     * 实现油猴脚本的fetch功能
     *
     * 提供与浏览器原生fetch API兼容的功能，允许脚本发送网络请求
     *
     * @param url 请求URL
     * @param options JSON格式的请求选项，包括method、headers、body等
     * @param callbacksName 回调函数名
     * @return 总是返回空JSON对象"{}"，实际结果通过JavaScript回调函数返回
     */
    @JavascriptInterface
    fun fetch(url: String, options: String, callbacksName: String) : String {
        val jsresponse = xmlHttpResponse()
        jsresponse.finalUrl = url

        // 油猴的脚本类
        val yyscriptvar = "window[\"mborwser_tm2\"]"
        val yyjiekou = "window.a${state.uuid}"

        state.coroutine?.launch {
            try {
                // 解析选项
                val optionsJson = JSONObject(options)
                val method = optionsJson.optString("method", "GET")
                val body = optionsJson.optString("body", "")
                val credentials = optionsJson.optString("credentials", "same-origin")
                val timeout = optionsJson.optInt("timeout", 0)
                val redirect = when(optionsJson.optString("redirect", "follow")) {
                    "follow" -> true
                    else -> false
                }

                // 解析请求头
                val headersMap = mutableMapOf<String, String>()
                optionsJson.optJSONObject("headers")?.let { jsonHeaders ->
                    jsonHeaders.keys().forEach { key ->
                        headersMap[key] = jsonHeaders.get(key).toString()
                    }
                }

                // 设置UA
                if (!headersMap.containsKey("User-Agent")) {
                    runBlocking {
                        headersMap["User-Agent"] = 应用配置.读取默认UA标识().first()
                    }
                }

                // 处理cookies
                if (credentials == "include" || credentials == "same-origin") {
                    CookieManager.getInstance().getCookie(url)?.let {
                        if (it.isNotEmpty()) headersMap["Cookie"] = it
                    }
                }

                // 执行请求
                val response = 执行网络请求(
                    url = url,
                    method = method,
                    headers = headersMap,
                    body = body,
                    redirect = redirect,
                    timeout = timeout
                )

                // 发送回调
                "${yyjiekou}.getTmp('${应用接口.写缓存(GsonUtils.toJson(response))}')".let { callbackContext ->
                    state.webview?.evaluateJavascript("${yyscriptvar}.fetchCallback(\"${callbacksName}\",$callbackContext)", null)
                }

            } catch (e: Exception) {
                Log.e("浏览框油猴", "fetch 错误: ${e.message}", e)
                jsresponse.status = -1
                jsresponse.statusText = e.toString()

                "${yyjiekou}.getTmp('${应用接口.写缓存(GsonUtils.toJson(jsresponse))}')".let { callbackContext ->
                    state.webview?.evaluateJavascript("${yyscriptvar}.fetchCallback(\"${callbacksName}\",null,$callbackContext)", null)
                }
            }
        }

        return "{}"
    }

    /**
     * 实现油猴脚本的 GM_xmlhttpRequest 功能，用于发送网络请求
     * 
     * 这个方法是油猴脚本最重要的API之一，允许脚本跨域发送HTTP请求。
     * 它模拟了桌面浏览器油猴扩展的网络请求功能，支持GET/POST等方法，
     * 并处理了各种参数如自定义头、cookies、重定向等。
     * 请求处理在协程中异步执行，通过JavaScript回调通知结果。
     *
     * @param method 请求方法，如'GET'、'POST'等
     * @param url_ 请求URL，相对路径会根据当前页面URL转为绝对路径
     * @param headers JSON格式的请求头
     * @param data POST请求的数据
     * @param redirect 是否跟随重定向
     * @param cookie 要发送的cookie
     * @param binary 是否返回二进制数据
     * @param nocache 是否禁用缓存
     * @param revalidate 是否重新验证缓存(此参数在当前实现中被忽略)
     * @param timeout 超时时间(毫秒)
     * @param context 上下文属性，会被添加到响应对象中
     * @param responseType 响应类型，如'text'、'arraybuffer'等
     * @param overrideMimeType 覆盖MIME类型
     * @param anonymous 是否在请求头中添加Origin字段
     * @param user 认证用户名
     * @param password 认证密码
     * @param callbacksName 回调函数名
     * @return 总是返回空JSON对象"{}"，实际结果通过JavaScript回调函数返回
     */
    @JavascriptInterface
    fun xmlhttpRequest(method : String, url_ : String,
                       headers : String, data : String, redirect : Boolean, cookie : String, binary : Boolean,
                       nocache : Boolean, revalidate : Boolean, timeout : Int, context : String, responseType : String,
                       overrideMimeType : String, anonymous : Boolean,
                       user : String, password : String, callbacksName:String): String {
        
        val url = 文本操作.取绝对地址(url_, state.地址.value)
        val jsresponse = xmlHttpResponse()
        jsresponse.finalUrl = url

        // 油猴的脚本类
        val yyscriptvar = "window[\"mborwser_tm2\"]"
        val yyjiekou = "window.a${state.uuid}"
        
        // 解析请求头
        val headersMap = mutableMapOf<String, String>()
        if (headers.isNotEmpty()) {
            try {
                JSONObject(headers).let { jsonHeaders ->
                    jsonHeaders.keys().forEach { key ->
                        headersMap[key] = jsonHeaders.get(key).toString()
                    }
                }
            } catch (e: Exception) {
                Log.e("浏览框油猴", "解析请求头失败: ${e.message}", e)
            }
        }
        
        // 设置UA
        if (!headersMap.containsKey("User-Agent")) {
            runBlocking {
                headersMap["User-Agent"] = 应用配置.读取默认UA标识().first()
            }
        }
        
        // 设置Cookie
        if (cookie.isNotEmpty()) {
            headersMap["Cookie"] = cookie
        } else {
            CookieManager.getInstance().getCookie(url)?.let {
                if (it.isNotEmpty()) headersMap["Cookie"] = it
            }
        }
        
        // 设置MIME类型
        if (overrideMimeType.isNotEmpty()) {
            headersMap["Accept"] = overrideMimeType
        }
        
        // 设置Origin
        if (anonymous) {
            headersMap["Origin"] = url
        }
        
        // 设置认证
        if (user.trim().isNotEmpty()) {
            val credential = Credentials.basic(user, password)
            headersMap["Authorization"] = credential
        }

        state.coroutine?.launch {
            try {
                // 发送onloadstart回调
                if (responseType != "stream") {
                    "${yyjiekou}.getTmp('${应用接口.写缓存(GsonUtils.toJson(jsresponse))}')".let { callbackContext ->
                        state.webview?.evaluateJavascript("${yyscriptvar}.xmlHttpcallback(\"${callbacksName}\",\"onloadstart\",\"${responseType}\",$callbackContext)", null)
                    }
                }
                
                // 执行请求
                val response = 执行网络请求(
                    url = url,
                    method = method,
                    headers = headersMap,
                    body = data,
                    redirect = redirect,
                    timeout = timeout,
                    binary = binary,
                    responseType = responseType
                )
                
                // 发送onload回调
                "${yyjiekou}.getTmp('${应用接口.写缓存(GsonUtils.toJson(response))}')".let { callbackContext ->
                    // 如果是stream类型，先发送onloadstart
                    if (responseType == "stream") {
                        state.webview?.evaluateJavascript("${yyscriptvar}.xmlHttpcallback(\"${callbacksName}\",\"onloadstart\",\"${responseType}\",$callbackContext)", null)
                    }
                    
                    // 发送onload回调
                    state.webview?.evaluateJavascript("${yyscriptvar}.xmlHttpcallback(\"${callbacksName}\",\"onload\",\"${responseType}\",$callbackContext)", null)
                }
                
            } catch (e: SocketTimeoutException) {
                jsresponse.status = -1
                jsresponse.statusText = "Timeout"
                
                "${yyjiekou}.getTmp('${应用接口.写缓存(GsonUtils.toJson(jsresponse))}')".let { callbackContext ->
                    state.webview?.evaluateJavascript("${yyscriptvar}.xmlHttpcallback(\"${callbacksName}\",\"ontimeout\",\"${responseType}\",$callbackContext)", null)
                }
            } catch (e: Exception) {
                Log.e("浏览框油猴", "xmlhttpRequest 错误: ${e.message}", e)
                jsresponse.status = -1
                jsresponse.statusText = e.toString()
                
                "${yyjiekou}.getTmp('${应用接口.写缓存(GsonUtils.toJson(jsresponse))}')".let { callbackContext ->
                    state.webview?.evaluateJavascript("${yyscriptvar}.xmlHttpcallback(\"${callbacksName}\",\"onerror\",\"${responseType}\",$callbackContext)", null)
                }
            }
        }

        return "{}"
    }

    /**
     * 获取临时存储的数据
     * 
     * 用于在JavaScript和Java之间传递大量数据，避免字符串长度限制。
     * 获取后会自动删除临时数据。
     *
     * @param sign 唯一标识，用于查找存储的数据
     * @return 存储的数据内容
     */
    @JavascriptInterface
    fun getTmp(sign : String) : String{
        应用接口.取缓存(sign).let {
            应用接口.删除缓存(sign)
            return it
        }
    }

    /**
     * XML HTTP响应对象
     * 
     * 用于构造与油猴脚本GM_xmlhttpRequest兼容的响应对象
     */
    class xmlHttpResponse{
        var finalUrl = "" //- 重定向后的最终URL
        var readyState = 4 //- 请求的readyState
        var status = 0 //- 请求的状态码
        var statusText = "" //- 请求的状态文本
        var responseHeaders : Headers ?= null //- 响应头
        var response = "" //- 响应数据，二进制数据会编码为base64
    }



    /**
     * 在当前浏览器页面打开URL（实现油猴脚本的GM_openInTab功能的变种）
     * 
     * @param sign 脚本标识
     * @param url 要打开的URL
     */
    @JavascriptInterface
    fun openUrl(sign: String, url: String?) {
        state.响应加载新的页面?.invoke(url?:return)
    }

    /**
     * 设置脚本的存储值（实现油猴脚本的GM_setValue功能）
     * 
     * 允许脚本以键值对形式永久存储数据，与桌面浏览器油猴扩展兼容。
     * 数据以JSON格式保存在文件中，每个脚本有独立的存储文件。
     *
     * @param sign 脚本标识，用于区分不同脚本的数据
     * @param key 键名
     * @param value 值，传null表示删除该键
     */
    @JavascriptInterface
    fun setValue(sign: String?, key: String?, value: String?) {
        if (sign.isNullOrBlank() || key.isNullOrBlank()) {
            Log.e("浏览框油猴", "setValue 参数错误: sign=$sign, key=$key")
            return
        }
        
        val 配置文件路径 = "${脚本存储目录}${sign}.json"
        
        // 获取或创建对应脚本的文件锁
        val 锁 = 文件锁.computeIfAbsent(sign) { ReentrantReadWriteLock() }
        
        锁.write {
            try {
                // 从缓存获取或加载JSON
                val json = 获取脚本配置JSON(sign)
                
                // 更新值
                if (value == null) {
                    if (json.has(key)) {
                        json.remove(key)
                    }
                } else {
                    json.put(key, value)
                }
                
                // 保存到文件
                FileIOUtils.writeFileFromString(File(配置文件路径), json.toString())
                
                // 更新缓存
                脚本数据缓存[sign] = json
                
            } catch (e: Exception) {
                Log.e("浏览框油猴", "setValue 出错: ${e.message}", e)
            }
        }
    }

    /**
     * 获取脚本的存储值（实现油猴脚本的GM_getValue功能）
     * 
     * 从永久存储中获取脚本数据，与桌面浏览器油猴扩展兼容。
     *
     * @param sign 脚本标识
     * @param key 键名
     * @return 存储的值，不存在则返回null
     */
    @JavascriptInterface
    fun getValue(sign: String, key: String): String? {
        if (sign.isBlank() || key.isBlank()) {
            Log.e("浏览框油猴", "getValue 参数错误: sign=$sign, key=$key")
            return null
        }
        
        // 获取或创建对应脚本的文件锁
        val 锁 = 文件锁.computeIfAbsent(sign) { ReentrantReadWriteLock() }
        
        return 锁.read {
            try {
                // 从缓存获取或加载JSON
                val json = 获取脚本配置JSON(sign)
                
                // 读取值
                if (json.has(key)) {
                    json.getString(key)
                } else {
                    null
                }
            } catch (e: Exception) {
                Log.e("浏览框油猴", "getValue 出错: ${e.message}", e)
                null
            }
        }
    }
    
    /**
     * 删除脚本的存储值（实现油猴脚本的GM_deleteValue功能）
     * 
     * 从永久存储中删除指定的键值对
     *
     * @param sign 脚本标识
     * @param key 要删除的键名
     */
    @JavascriptInterface
    fun delValue(sign: String, key: String) {
        setValue(sign, key, null)
    }
    
    /**
     * 获取脚本的配置JSON
     * 
     * 从缓存或文件加载脚本的配置数据
     * 
     * @param sign 脚本标识
     * @return 配置数据的JSON对象
     */
    private fun 获取脚本配置JSON(sign: String): JSONObject {
        // 先从缓存中查找
        脚本数据缓存[sign]?.let { return it }
        
        // 缓存中没有，从文件加载
        val 配置文件 = File("${脚本存储目录}${sign}.json")
        
        return if (配置文件.exists()) {
            try {
                val jsonStr = FileIOUtils.readFile2String(配置文件)
                val json = JSONObject(jsonStr.ifBlank { "{}" })
                // 放入缓存
                脚本数据缓存[sign] = json
                json
            } catch (e: JSONException) {
                Log.e("浏览框油猴", "解析配置文件失败: ${e.message}", e)
                JSONObject().also { 脚本数据缓存[sign] = it }
            }
        } else {
            JSONObject().also { 脚本数据缓存[sign] = it }
        }
    }

    /**
     * 列出脚本所有存储的键（实现油猴脚本的GM_listValues功能）
     * 
     * 返回以换行符分隔的键名列表
     *
     * @param sign 脚本标识
     * @return 所有键名，以换行符分隔的字符串
     */
    @JavascriptInterface
    fun listValues(sign: String) : String {
        if (sign.isBlank()) {
            return " \n" // 保持原有行为，返回非空字符串
        }
        
        // 获取或创建对应脚本的文件锁
        val 锁 = 文件锁.computeIfAbsent(sign) { ReentrantReadWriteLock() }
        
        return 锁.read {
            try {
                // 从缓存获取或加载JSON
                val json = 获取脚本配置JSON(sign)
                
                // 构建键列表
                val keys = StringBuilder()
                json.keys().forEach { key ->
                    keys.append(key).append("\n")
                }
                
                // 确保不返回空字符串
                if (keys.isEmpty()) " \n" else keys.toString()
                
            } catch (e: Exception) {
                Log.e("浏览框油猴", "listValues 出错: ${e.message}", e)
                " \n" // 发生错误时返回非空字符串
            }
        }
    }

    /**
     * 下载文件（实现油猴脚本的GM_download功能之一）
     * 
     * 无文件名版本，仅为API兼容，实际未实现功能
     *
     * @param url 要下载的文件URL
     */
    @JavascriptInterface
    fun download(url: String) {
        state.coroutine?.launch {
            应用接口.请求下载(url,null)
        }
    }

    /**
     * 下载文件（实现油猴脚本的GM_download功能）
     * 
     * 下载指定URL的文件并保存为指定文件名
     *
     * @param url 要打开的URL
     * @param name 保存的文件名
     */
    @JavascriptInterface
    fun download(url: String, name: String) {
        state.coroutine?.launch {
            应用接口.请求下载(url,name)
        }
    }

    /**
     * 获取脚本资源文本（实现油猴脚本的GM_getResourceText功能）
     * 
     * TODO 获取在脚本中定义的资源文本内容
     *
     * @param sign 脚本标识
     * @param key 资源的键名
     * @return 资源文本内容，不存在则返回null
     */
    @JavascriptInterface
    fun getResourceText(sign: String, key: String): String? {
        /*PluginUtils.scripts.forEach {
            if (it.unid == sign) {
                it.resource[key]?.let { url ->
                    return NetUtils.get(url, null, -1)
                }
            }
        }*/
        return null
    }

    /**
     * TODO 获取脚本资源URL（实现油猴脚本的GM_getResourceURL功能）
     * 
     * 获取在脚本中定义的资源URL，以base64编码返回
     *
     * @param sign 脚本标识
     * @param key 资源的键名
     * @return 资源URL的base64编码，不存在则返回null
     */
    @JavascriptInterface
    fun getResourceUrl(sign: String, key: String): String? {
        /*PluginUtils.scripts.forEach {
            if (it.unid == sign) {
                it.resource[key]?.let { url ->
                    return EncodeUtils.base64Encode2String(url.toByteArray())
                }
            }
        }*/
        return null
    }

    /**
     * 显示输入对话框
     * 
     * 显示一个输入对话框，等待用户输入
     * 这是同步调用，会阻塞脚本执行，直到用户输入或超时
     *
     * @param name 对话框标题
     * @return 用户输入的文本
     */
    @JavascriptInterface
    fun input(name : String) : String{
        var str = ""
        val await = CountDownLatch(1)

        // 尝试获取应用上下文并使用主线程显示对话框
        try {
            // 使用state.coroutine确保安全地在UI线程执行
            state.coroutine?.launch {
                // 使用当前活动的Context创建对话框
                val context = state.webview?.context ?: return@launch
                
                val builder = AlertDialog.Builder(context)
                builder.setTitle(name)
                
                // 创建编辑框
                val input = android.widget.EditText(context)
                input.setSingleLine()
                input.setPadding(50, 30, 50, 30)
                
                // 设置布局参数
                val layoutParams = android.widget.LinearLayout.LayoutParams(
                    android.widget.LinearLayout.LayoutParams.MATCH_PARENT,
                    android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
                )
                layoutParams.setMargins(60, 0, 60, 0)
                input.layoutParams = layoutParams
                
                // 将编辑框添加到对话框
                builder.setView(input)
                
                // 添加确定按钮
                builder.setPositiveButton("确定") { _, _ ->
                    str = input.text.toString()
                    await.countDown()
                }
                
                // 添加取消按钮
                builder.setNegativeButton("取消") { _, _ ->
                    await.countDown()
                }
                
                // 对话框关闭时也要释放锁
                builder.setOnCancelListener {
                    await.countDown()
                }
                
                // 显示对话框
                builder.show()
            } ?: run {
                // 协程上下文不可用，直接返回
                Log.e("浏览框油猴", "无法获取协程上下文，输入对话框创建失败")
                return ""
            }
        } catch (e: Exception) {
            Log.e("浏览框油猴", "显示输入对话框失败: ${e.message}", e)
            return ""
        }
        
        // 异步转同步，延时10秒，超过则超时不作处理
        try {
            await.await(10, TimeUnit.SECONDS)
        } catch (e: InterruptedException) {
            Log.e("浏览框油猴", "输入对话框等待超时", e)
        }
        
        return str
    }

    /**
     * 显示通知（实现油猴脚本的GM_notification功能）
     * 
     * 显示一个弹出通知，可设置自动关闭
     *
     * @param title 通知标题
     * @param text 通知内容
     * @param image 通知图片URL（当前实现未使用）
     * @param highlight 是否高亮显示发送通知的标签页（当前实现未使用）
     * @param silent 是否静音（当前实现未使用）
     * @param timeout 通知自动关闭的超时时间(毫秒)，0表示不自动关闭
     * @return 0表示用户点击了确定，-1表示超时关闭
     */
    @JavascriptInterface
    fun notification(title : String, text : String, image : String, highlight : Boolean, silent : Boolean, timeout : Int) : Int{
        val await = CountDownLatch(1)
        var dismiss = false
        
        // 尝试获取应用上下文并使用主线程显示对话框
        try {
            // 使用state.coroutine确保安全地在UI线程执行
            state.coroutine?.launch {
                // 使用当前活动的Context创建对话框
                val context = state.webview?.context ?: return@launch
                
                val builder = AlertDialog.Builder(context)
                if (title.isNotEmpty()) builder.setTitle(title)
                builder.setMessage(text)
                builder.setPositiveButton("确定") { dialog: DialogInterface?, which: Int ->
                    dismiss = true
                    await.countDown()
                }
                
                // 添加对话框关闭监听器
                builder.setOnCancelListener {
                    await.countDown()
                }
                
                builder.show()
            } ?: run {
                // 协程上下文不可用，直接返回
                Log.e("浏览框油猴", "无法获取协程上下文，通知对话框创建失败")
                return -1
            }
        } catch (e: Exception) {
            Log.e("浏览框油猴", "显示通知对话框失败: ${e.message}", e)
            return -1
        }
        
        // 异步转同步，延时设定时间，超过则超时不作处理
        try {
            await.await(if (timeout == 0) 300000L else timeout.toLong(), TimeUnit.MILLISECONDS)
        } catch (e: InterruptedException) {
            Log.e("浏览框油猴", "通知对话框等待超时", e)
        }

        // 点击返回零，超时返回-1
        return if (dismiss) 0 else -1
    }

    /**
     * 获取脚本信息（实现油猴脚本的GM_info功能）
     * 
     * 返回当前环境和脚本的信息
     *
     * @param sign 脚本标识
     * @return 包含脚本和环境信息的JSON字符串
     */
    @JavascriptInterface
    fun info(sign: String): String {
        // 返回脚本的一些信息
        val json = JSONObject()
        json.put("scriptHandler", "Tampermonkey")
        json.put("downloadMode", "native")

        /*when (AppConfigUtils.x下载器) {
            DataType.下载器_默认 -> json.put("downloadMode", "native")
            DataType.下载器_ADM -> json.put("downloadMode", "ADM")
            DataType.下载器_IDM -> json.put("downloadMode", "IDM")
        }*/

        val scriptInfo = JSONObject()
        scriptInfo.put("author", "")
        json.put("script", scriptInfo)

        return json.toString()
    }

    /**
     * 记录日志
     * 
     * 将脚本的日志记录到Android日志系统
     *
     * @param str 要记录的日志内容
     */
    @JavascriptInterface
    fun log(str: String) {
        mlog("浏览框-油猴回调", str)
    }

    /**
     * 油猴脚本注入完成的回调
     * 
     * 当油猴兼容脚本已成功注入页面时调用此方法
     */
    @JavascriptInterface
    fun initend() {
        state.油猴兼容脚本已注入 = true
    }

    /**
     * 在新标签页打开URL（实现油猴脚本的GM_openInTab功能）
     * 
     * @param url 要打开的URL
     */
    @JavascriptInterface
    fun openInTab(url : String){
        state.响应加载新的页面?.invoke(url)
    }

    /**
     * 复制文本到剪贴板（实现油猴脚本的GM_setClipboard功能）
     * 
     * @param str 要复制的文本
     */
    @JavascriptInterface
    fun setClipboard(str : String){
        ClipboardUtils.copyText(str)
    }

    /**
     * TODO 注销油猴脚本菜单命令（实现油猴脚本的GM_unregisterMenuCommand功能）
     * 
     * 从脚本菜单中移除指定ID的命令
     *
     * @param sign 脚本标识
     * @param id 命令ID
     */
    @JavascriptInterface
    fun unregisterMenuCommand(sign: String, id: Int) {
        /*try {
            webkt.webData.script_menu[sign].let {
                if (it is EON) {
                    if (it.containsKey(id.toString())) {
                        it.remove(id.toString())
                    }
                }
            }
        } catch (e: Exception) {
            Log.e("浏览框油猴", "注销脚本菜单命令失败: ${e.message}", e)
        }*/
    }

    /**
     * todo 注册油猴脚本菜单命令（实现油猴脚本的GM_registerMenuCommand功能）
     * 
     * 在脚本菜单中添加一个命令
     *
     * @param sign 脚本标识
     * @param id 命令ID
     * @param name 命令名称
     */
    @JavascriptInterface
    fun registerMenuCommand(sign: String, id: Int, name: String) {
        /*try {
            if (!webkt.webData.script_menu.containsKey(sign)) {
                webkt.webData.script_menu[sign] = EON()
            }
            webkt.webData.script_menu[sign].let {
                if (it is EON) {
                    it[id.toString()] = name
                }
            }
        } catch (e: Exception) {
            Log.e("浏览框油猴", "注册脚本菜单命令失败: ${e.message}", e)
        }*/
    }
}